//线程局部存储

// 该count叫做线程的局部存储！
__thread int count = 1;
// 线程局部存储有什么用？全局变量，我又不想让这个全局变量被其他线程看到！
// 线程局部存储，只能存储内置类型和部分指针

std::string Addr(int &c)
{
    char addr[64];
    snprintf(addr, sizeof(addr), "%p", &c);
    return addr;
}

void *routine1(void *args)
{
    (void)args;
    while (true)
    {
        std::cout << "thread - 1, count = " << count << "[我来修改count], "
                  << "&count: " << Addr(count) << std::endl;
        count++;
        sleep(1);
    }
}

void *routine2(void *args)
{
    (void)args;
    while (true)
    {
        std::cout << "thread - 2, count = " << count
                  << ", &count: " << Addr(count) << std::endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid1, tid2;
    pthread_create(&tid1, nullptr, routine1, nullptr);
    pthread_create(&tid2, nullptr, routine2, nullptr);

    pthread_join(tid1, nullptr);
    pthread_join(tid2, nullptr);

    return 0;
}




//一个线程独立的栈，另一个线程如果想访问是能访问到的
int *p = nullptr;

void *threadrun(void *args)
{
    int a = 123;

    p = &a;

    while(true) {sleep(1);}
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, nullptr);

    while(true)
    {
        std::cout << "*p : " << *p << std::endl;
        sleep(1);
    }

    pthread_join(tid, nullptr);
    return 0;
}



//用原生线程库做多线程操作
const int num = 10;
void *routine(void *args)
{
	sleep(1);
    std::string name = static_cast<const char *>(args);
	delete((char*)args);
	
    int cnt = 5;
    while (cnt--)
    {
        std::cout << "new线程名字: " << name << std::endl;
        sleep(1);
    }
    return nullptr;
}

int main()
{
    std::vector<pthread_t> tids;
    for (int i = 0; i < num; i++)
    {
        pthread_t tid;
		
		// char id[64]; 
		// bug？？传递的id是for循环内的一个临时数组，创建线程的时候传递的id属于该数组的起始地址，
		// routine拿到的数组内容1s后才使用，这期间数组内容有可能被改变
        
		char *id = new char[64]; // 每次循环都要给每个线程申请一块堆空间
        snprintf(id, 64, "thread-%d", i);
        int n = pthread_create(&tid, nullptr, routine, id);
        if (n == 0)
            tids.push_back(tid);
        else
            continue;
    }

    for (int i = 0; i < num; i++)
    {
        // 一个一个的等待
        int n = pthread_join(tids[i], nullptr);
        if (n == 0)
        {
            std::cout << "等待新线程成功" << std::endl;
        }
    }

    return 0;
}



//如果主线程不想再关心新线程，而是当新线程结束的时候，让它自己释放
void *routine(void *args)
{
	//新线程把自己分离
	// pthread_detach(pthread_self());
	// std::cout << "新线程被分离" << std::endl;
	
	int cnt=5;
	while(cnt--)
	{
		std::cout << "我是一个新线程"<< std::endl;
        sleep(1);
	}
	return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, (void*)"thread-1");
	
	// 主线程分离新线程
	pthread_detach(tid);
	std::cout << "新线程被分离" << std::endl;
	
    int cnt = 5;
    while (cnt--)
    {
        std::cout << "我是主线程 " << std::endl;
        sleep(1);
    }
	
	// 如果线程被设置为分离状态，join会失败！！
	int n = pthread_join(tid, nullptr);
    if (n != 0)
    {
        std::cout << "pthread_join error: " << strerror(n) << std::endl;
    }
    else
    {
        std::cout << "pthread_join success: " << strerror(n) << std::endl;
    }

	return 0;
}




// 线程终止
void *routine(void *args)
{
	Task* t=static_cast<Task*>(args);	
	
	// sleep(100); // 验证pthread_cancel
	
	sleep(1);
	Result* res=new Result(t->Execute());
	sleep(1);
    //return res;
	//exit(13);
	pthread_exit(res);
	std::cout<<"新线程不应该看到这里！"<<std::endl;
	
}

int main()
{
    pthread_t tid;
    Task *t = new Task(10, 20);
    pthread_create(&tid, nullptr, routine, t);
	
	// 验证pthread_cancel
	// sleep(5); 
	//pthread_cancel(tid);
	//std::cout<<"新线程被取消"<<std::endl;
	//void* ret=nullptr;
	//pthread_join(tid,&ret)
	//std::cout<<"新线程结束，运行结果："<<(long long int) ret<<std::endl;

	Result* ret=nullptr;
    pthread_join(tid, (void**)&ret);
	int n=ret->GetResult();
	std::cout<<"新线程结束，运行结果："<<n<<std::endl;
	delete t;
	delete ret;
    return 0;
}


// 给线程传递的参数和返回值，可以是任意类型
class Task
{
public:
    Task(int a, int b) : _a(a), _b(b) {}
    int Execute()
    {
        return _a + _b;
    }
    ~Task() {}
private:
    int _a;
    int _b;
};

class Result
{
public:
    Result(int result) : _result(result)
    {
    }
    int GetResult() { return _result; }
    ~Result() {}
private:
    int _result;
};

void *routine(void *args)
{
	Task* t=static_cast<Task*>(args);	
	sleep(1);
	Result* res=new Result(t->Execute());
	sleep(1);
    return res;
}

int main()
{
    pthread_t tid;
    Task *t = new Task(10, 20);
    pthread_create(&tid, nullptr, routine, t);
	Result* ret=nullptr;
    pthread_join(tid, (void**)&ret);
	int n=ret->GetResult();
	std::cout<<"新线程结束，运行结果："<<n<<std::endl;
	delete t;
	delete ret;
    return 0;
}



// 线程传参和返回值
int flag = 100;
void showtid(pthread_t &tid)
{
    printf("tid: 0x%lx\n", tid);
}

std::string FormatId(const pthread_t &tid) // 可重入函数
{
    char id[64];
    snprintf(id, sizeof(id), "0x%lx", tid);
    return id;
}

// code done, result ok
// code done, result not ok
// code no finish
void *routine(void *args)
{
    std::string name = static_cast<const char *>(args);
    pthread_t tid = pthread_self();
    int cnt = 5;
    while (cnt)
    {
        std::cout << "我是一个新线程: 我的名字是: " << name << " 我的Id是: " << FormatId(tid) << std::endl;
        sleep(1);
        cnt--;
        flag++;
    }
    return (void*)123;// 暂时：线程退出的时候的退出码
}

int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, routine, (void *)"thread-1");

    showtid(tid);

    int cnt = 5;
    while (cnt)
    {
        std::cout << "我是main线程: 我的名字是: main thread" << " 我的Id是: " 
            << FormatId(pthread_self()) << ", flag: " << flag << std::endl;
        sleep(1);
        cnt--;
    }

    void *ret = nullptr; // ret也是一个变量！！也有空间哦！
	//整形变量是一个变量内部放整数，整形是一种类型，整形变量是一个空间将来做左值做右值代表不同含义。
	//指针变量也是一个变量内部放地址，指针变量也有空间

    // 等待的目标线程，如果异常了，整个进程都退出了，包括main线程，所以，join异常，没有意义，看也看不到！
    // jion都是基于：线程健康跑完的情况，不需要处理异常信号，异常信号，是进程要处理的话题！！！
    pthread_join(tid, &ret); // 为什么在join的时候，没有见到异常相关的字段呢？？

    std::cout << "ret is : " << (long long int)ret << std::endl;

    return 0;
}



//简单的线程创建和等待，获得线程的id
void showtid(pthread_t &tid)
{
    printf("tid: 0x%lx\n", tid);
}

std::string FormatId(const pthread_t &tid) //可重入函数
{
    char id[64];
    snprintf(id, sizeof(id), "0x%lx", tid);
    return id;
}

void *routine(void *args)
{
    std::string name = static_cast<const char *>(args);
	pthread_t tid = pthread_self(); // 获得线程的id
    int cnt = 5;
    while (cnt)
    {
        std::cout << "我是一个新线程: 我的名字是: " << name  <<" 我的Id是: " << FormatId(tid) << std::endl;
        sleep(1);
        cnt--;
    }
    return nullptr;
}

int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, routine, (void *)"thread-1");
	(void)n;
	
	showtid(tid); // 演示创建线程获得的tid
	
	pthread_join(tid,nullptr);
	
	return 0;
}



//C++11当中的多线程
void hello()
{
    while (true)
    {
        std::cout << "新线程: hello world, pid: " << getpid() << std::endl;
        sleep(1);
    }
}
int main()
{
    std::thread t(hello);

    while (true)
    {
        std::cout << "我是主线程..." << ", pid: " << getpid() << std::endl;
        sleep(1);
    }

    t.join();
    return 0;
}



//看到线程是用轻量级进程模拟的，创建多线程
void *threadrun(void *args)
{
    std::string name = (const char*)args;
    while(true)
    {
        sleep(1);
        std::cout << "我是新线程: name: " << name << ", pid: " << getpid() << std::endl;
		
		//验证线程出异常
		// int a = 10;
        // a /= 0;

    }
    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, (void*)"thread-1");
    while(true)
    {
        std::cout << "我是主线程..." << ", pid: " << getpid() << std::endl;
        sleep(1);
    }
    return 0;
 }
